package com.nlp.visualization.service.tasks;

import com.google.gson.Gson;
import com.nlp.visualization.common.CONSTANTS;
import com.nlp.visualization.core.seg.ISegmentService;
import com.nlp.visualization.core.seg.SegmentFactory;
import com.nlp.visualization.core.seg.SegmentType;
import com.nlp.visualization.core.seg.filter.SegFilter;
import com.nlp.visualization.pojo.NLP.weibo.WeiboCSVEntity;
import com.nlp.visualization.pojo.NLP.weibo.WeiboContentEntity;
import com.nlp.visualization.pojo.NLP.weibo.WeiboSegEntity;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.RecursiveAction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.nlp.visualization.common.CONSTANTS.TASK_MAX;

public class WeiboSeg2SQLTask extends RecursiveAction {

    Logger logger = LoggerFactory.getLogger(WeiboSeg2SQLTask.class);
    // 每个"小任务"最多只50个数
    private static final int MAX = TASK_MAX;

    private int start;
    private int end;
    private List<WeiboCSVEntity> lines;
    private ConcurrentLinkedQueue<String> queue;
    private SegmentType method;
    private SegFilter filter;

    public WeiboSeg2SQLTask(int start, int end, List lines, ConcurrentLinkedQueue<String> queue, SegmentType method, SegFilter filter) {
        this.start = start;
        this.end = end;
        this.lines = lines;
        this.queue = queue;
        this.method = method;
        this.filter = filter;

    }

    @Override
    protected void compute() {
        // 当end-start的值小于MAX时候，开始执行任务
        if ((end - start) < MAX) {
            for (int i = start; i < end; i++) {
                Gson gson = new Gson();
                //将文件读到的json转换成初始文件的实体
                WeiboCSVEntity csv = lines.get(i);
                //将微博的内容转成微博info的对象
                WeiboContentEntity weiboContent = gson.fromJson(csv.getWeibo_info().replaceAll("\\\\", ""), WeiboContentEntity.class);
                //实例化一个要返回的对象
                WeiboSegEntity seg = new WeiboSegEntity();
                //判断是否是原创微博
                if (!weiboContent.isIs_reprint_weibo()) {
                    //插入原文本信息
                    queue.add(InsertContentSQL(weiboContent.getWeibo_content().split("\u200B\u200B\u200B")[0], csv.getWeibo_id()));
                    //分词过程，往queue里面添加信息
                    queue.addAll(fillSeg(csv, weiboContent, method, filter));
                } else {
                    //不是原创微博，跳过本条记录
                    continue;
                }
            }
        } else {
            // 将大任务分解成两个小任务
            int middle = (start + end) / 2;
            WeiboSeg2SQLTask left = new WeiboSeg2SQLTask(start, middle, lines, queue, method, filter);
            WeiboSeg2SQLTask right = new WeiboSeg2SQLTask(middle, end, lines, queue, method, filter);
            // 并行执行两个小任务
            left.fork();
            right.fork();
        }
    }


    /**
     * 返回插入微博原文本的SQL语言
     *
     * @param content
     * @param weibo_id
     * @return
     */
    private String InsertContentSQL(String content, String weibo_id) {

        content = filterEmoji(content);
        content = content.replaceAll("'", "\\\\'");

        return "INSERT INTO " + CONSTANTS.WEIBO_CONTENT_TABLE_NAME + "(" + CONSTANTS.WEIBO_CONTENT_TABLE_ID + "," + CONSTANTS.WEIBO_CONTENT_TABLE_CONTENT + ") " +
                "VALUES('" + weibo_id + "','" + content + "');\n";

    }


    /**
     * 填充返回的数据
     *
     * @param csv          一条csv数据的实体
     * @param weiboContent 一条微博内容的实体
     * @param method       采用分词的方式
     */
    private List<String> fillSeg(WeiboCSVEntity csv, WeiboContentEntity weiboContent, SegmentType method, SegFilter filter) {

        ISegmentService segmentService = SegmentFactory.getInstance();
        try {
            String content = weiboContent.getWeibo_content().split("\u200B\u200B\u200B")[0];
            content = filterEmoji(content);
            List<String> segResults = segmentService.executeSeg(content, method, filter);
            Iterator iterator = segResults.iterator();
            List<String> SQLList = new ArrayList<>();
            //通过Hash表获取要插入的表名
            String tableName = CONSTANTS.TABLE_NAME_HASH_MAP.get(getHashValue(csv.getUser_id()));
            int count = 0;
            while (iterator.hasNext()) {
                String term = (String) iterator.next();
                if (term.trim().equals(""))
                    continue;
                String SQL = "";
                String[] terms = term.split("/");
                String word = "";
                String pos = "";
                word = terms[0];
                if (terms.length > 1)
                    pos = terms[1];
                //拼凑SQL
                SQL = "INSERT INTO " + tableName + "(words_belong_weibo_id,words_belong_user_id,words_publish_time,id,item,byte_length,formal" +
                        ",named_entity,part_of_speech) VALUES(" + "'" + csv.getWeibo_id() + "'," + "'" + csv.getUser_id() + "',"
                        + "'" + getTimeFromStr(weiboContent.getPublish_time()) + "'," + "'" + count + "'," + "'" + word + "'," + "'" + term.toString().getBytes().length + "',"
                        + "' '," + "' '," + "'" + pos + "');\n";
                count++;
                SQLList.add(SQL);

            }
            return SQLList;

        } catch (Exception e) {
            logger.error("分词异常");
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 提取微博中的时间
     *
     * @param str
     * @return
     */
    private String getTimeFromStr(String str) {
        str = str.replace("今天", "2017-10-19");
        Pattern pattern = Pattern.compile("[0-9]{4}[-][0-9]{1,2}[-][0-9]{1,2}[ ][0-9]{1,2}[:][0-9]{1,2}[:][0-9]{1,2}");
        Matcher matcher = pattern.matcher(str);
        String dateStr = "";
        if (matcher.find()) {
            dateStr = matcher.group(0);
        }
        if (dateStr.equals("")) {
            pattern = Pattern.compile("[0-9]{1,2}月[0-9]{1,2}日[ ][0-9]{1,2}[:][0-9]{1,2}");
            matcher = pattern.matcher(str);
            if (matcher.find()) {
                dateStr = matcher.group(0);
                dateStr = dateStr.replace("月", "-");
                dateStr = dateStr.replace("日", "");
                dateStr = "2017-" + dateStr + ":00";
            }

        }
        if (dateStr.equals(""))
            return "2017-10-19 00:00:00";
        return dateStr.toString();
    }


    /**
     * 自定义的Hash方法，返回0-9
     *
     * @param id
     * @return
     */
    private int getHashValue(String id) {

        return ((id.charAt(0) - '0') + (id.charAt(id.length() - 1) - '0') * 7) % 10;

    }

    private static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
                || (codePoint == 0xD)
                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

    /**
     * 过滤emoji 或者 其他非文字类型的字符
     *
     * @param source
     * @return
     */
    public static String filterEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return source;
        }
        StringBuilder buf = null;
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (isEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }
                buf.append(codePoint);
            }
        }
        if (buf == null) {
            return source;
        } else {
            if (buf.length() == len) {
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }
    }

}
